package com.shareware.common.memory.entity

import android.os.Process
import com.shareware.common.DEFAULT
import com.shareware.common.utils.log
import com.shareware.common.utils.safeApply
import com.shareware.common.utils.safeLet
import org.json.JSONObject
import java.io.File
import java.util.regex.Pattern

/**
 * desc: 功能描述
 * email: mobiledeveloper@qq.com
 */
class StatusInfo(pid: Int = Process.myPid()) {
    val state: String
    val fdSize: Int
    val vmSizeK: Int
    val vmRssK: Int
    val vmSwapK: Int
    val threads: Int
    val oomAdj: Int
    val oomScoreAdj: Int

    init {
        convertPROCStatus(pid).run {
            fun Map<String, String>.getString(key: String) = get(key) ?: "unknown"

            fun Map<String, String>.getInt(key: String): Int {
                getString(key).let {
                    val matcher = Pattern.compile("\\d+").matcher(it)
                    while (matcher.find()) {
                        return matcher.group().toInt()
                    }
                }
                return -2
            }
            state = getString("State").trimIndent()
            fdSize = getInt("FDSize")
            vmSizeK = getInt("VmSize")
            vmRssK = getInt("VmRSS")
            vmSwapK = getInt("VmSwap")
            threads = getInt("Threads")
            oomAdj = getOomAdj(pid)
            oomScoreAdj = getOomScoreAdj(pid)
        }
    }

    private fun getOomAdj(pid: Int): Int = safeLet(defVal = Int.MAX_VALUE) {
        File("/proc/$pid/oom_adj").useLines {
            it.first().toInt()
        }
    }

    private fun getOomScoreAdj(pid: Int): Int = safeLet(defVal = Int.MAX_VALUE) {
        File("/proc/$pid/oom_score_adj").useLines {
            it.first().toInt()
        }
    }

    private fun convertPROCStatus(pid: Int): Map<String, String> {
        safeApply {
            File("/proc/${pid}/status").useLines { seq ->
                return seq.flatMap {
                    val split = it.split(":")
                    if (split.size == 2) {
                        return@flatMap sequenceOf(split[0] to split[1])
                    } else {
                        log(DEFAULT, "ERROR : $it")
                        return@flatMap emptySequence()
                    }
                }.toMap()
            }
        }
        return emptyMap()
    }

    override fun toString(): String {
        return String.format(
            "%-21s %-21s %-21s %-21s %-21s %-21s %-21s %-21s",
            "State=$state",
            "FDSize=$fdSize",
            "VmSize=$vmSizeK K",
            "VmRss=$vmRssK K",
            "VmSwap=$vmSwapK K",
            "Threads=$threads",
            "oom_adj=$oomAdj",
            "oom_score_adj=$oomScoreAdj"
        )
    }

    fun toJson() = safeLet(defVal = JSONObject()) {
        JSONObject().apply {
            put("state", state)
            put("vmSize", vmSizeK)
            put("vmRss", vmRssK)
            put("vmSwap", vmSwapK)
            put("threads", threads)
            put("fdSize", fdSize)
            put("oom_adj", oomAdj)
            put("oom_score_adj", oomScoreAdj)
        }
    }
}